<?php
/**
 * 
 * @author yusaint
 * @since 2014-3-9
 * @project Pfinal
 */
abstract class Pfinal_Model_Statement {
	/**
	 * basic option
	 * @var unknown_type
	 */
	const OPT_INSERT=' insert into ';
	const OPT_UPDATE=' update ';
	const OPT_WHERE=' where ';
	const OPT_SELECT=' select ';
	
	const OPT_FROM	=' from ';
    const OPT_GROUPBY=' group by ';
	const OPT_ORDERBY=' order by ';
	const OPT_AND	=' and ';
	const OPT_OR	=' or ';
    const OPT_LIMIT=' limit ';
	
    protected $tableName;
    protected $alias = null;
    protected $on;
    protected $orderClause = array();
    protected $groupClause = array();
    protected $count;
    protected $offset;
    protected $fields = array();
	protected $_where=array();
	protected $whereCols=array();
	
	
	/**
	 * @param unknown_type $col
	 * @return string
	 */
	protected function quote($col){
		return $col;
	}
	
	
	/**
	 * @return the $on
	 */
	public function getOn() {
		return $this->on;
	}

	/**
	 * @param field_type $on
	 */
	public function setOn($on) {
		$this->on = $on;
	}

	/**
	 * @return the $tableName
	 */
	public function getTableName() {
		return $this->tableName;
	}
	
	/**
	 * @param Ambigous <string, unknown> $tableName
	 */
	public function setTableName($tableName) {
		$this->tableName = $tableName;
	}
	
	/**
	 * @return the $fields
	 */
	public function getFields() {
		if (!empty($this->fields)){
			if (!is_array($this->fields)){
				$this->fields = array($this->fields);
			}
		}
		return $this->fields;
	}
	
	/**
	 * [orderBy description]
	 * @param  [type] $orderBy [description]
	 * @param  string $order   [description]
	 * @return [type]          [description]
	 */
	public function orderBy($orderBy, $order = 'desc')
	{
		if (!empty($orderBy)) {
			$this->orderClause[] = trim($orderBy) . ' ' . trim($order);
		}
		return $this;
	}
	/**
	 * [groupBy description]
	 * @param  [type] $group [description]
	 * @return [type]        [description]
	 */
	public function groupBy($group)
	{
		if (!empty($group)) {
			if(!is_array($group)){
				$group=trim($group);
				if(in_array($group,$this->groupClause)){
					return $this;
				}
				$this->groupClause[] = $group;
			}else{				
				$this->groupClause=array_merge($this->groupClause,$group);				
			}
		}
		return $this;
	}
	
	
	/**
	 * @param unknown_type $count
	 * @param unknown_type $offset
	 * @throws StatementException
	 */
	public function limit($count, $offset = null) {
		if (isset($count))
			$this->count = $count;
		if (isset($offset) && !isset($count)) {
			$errMsg=sprintf('ilegal offset or count value given');
			throw new Pfinal_Exception_Runtime($errMsg);
		}
		if (isset($offset))
			$this->offset = $offset;
		return $this;
	}
	
	/**
	 * [from description]
	 * @param  [type] $from  [description]
	 * @param  [type] $field [description]
	 * @return Pfinal_Model_Statement       [description]
	 */
	public function from($from,$field='*'){
		if(is_array($from)){
			$tableName = $from[0];
			$alias = isset($from[1])?$from[1]:null;
		}else{
			$tableName=$from;
			$alias=null;
		}
		if (isset($tableName) && $tableName != '')
			$this->tableName = $tableName;
		if (isset($alias) &&!isset($tableName)) {
			$errMsg=sprintf('the doris table name and reportengine templateName must be assigned');
			throw new Pfinal_Exception_Runtime($errMsg);
		} 
		if(isset($alias)) {
			$this->alias = $alias;
		}
		$this->fields = $field;
		//var_dump($this->fields);
		return $this;
	}
	
	
	/**
	 * value是这样的一个结构
	 * value=>{op:操作符,v:'值'}
	 * 当存在op字段的时候，会用这个op替换默认的操作符
	 * @param unknown_type $col
	 * @param unknown_type $value
	 */
	protected  function _where($colName,$colValue,$op){
		if(is_null($colValue))
			return $this;
		//检查默认值中的key operator
		//支持like操作符 like %?% ?% 这种
		$matched=array();
		if (preg_match('/^(?P<key>\S+\s*)(?P<op>(=|(>=)|(<=)|(!=)|(>)|(<)|(IN\s*)|(NOTIN\s*)|(like\s*)))[(\(\s*\?)|(\?)|((?P<prefix>%?)\?(?P<sufix>%?))]/i', $colName,$matched)){
			if(!isset($matched['key'])){
				$errMsg=sprintf('the column name is missing in the colunm %s',$colName);
				throw new Pfinal_Exception_Runtime($errMsg);
			}
			if(!isset($matched['op'])){
				$errMsg=sprintf('at least one operator is expected in the colunm %s',$colName);
				throw new Pfinal_Exception_Runtime($errMsg);
			}
		}
		$matched['op'] = trim($matched['op']);
		if (in_array($matched['op'], array('IN','NOTIN'))) {
			if (!is_array($colValue)){
					$errMsg=sprintf('the type of value[%s] is :%s,but of the value of the colunm %s must be a array,because the specific operator is %s',print_r($colValue,true),gettype($colValue),$colName,$matched['op']);
					throw new Pfinal_Exception_Runtime($errMsg);
			}elseif (is_array($colValue)&&empty($colValue)) {
				//如果in操作符，并且值为空，这种case，视为NULL，直接略过
				return $this;
			}	
			$prefix = isset($this->alias)?$this->alias:$this->tableName;
			foreach ($colValue as $k=>$v){
				if (is_string($v)){
					$colValue[$k] = '\''.$v.'\'';
				}
			}
			$this->whereCols[]=array($op,sprintf('%s.%s %s(%s)',$prefix,$matched['key'],$matched['op'],implode(',',$colValue)));
		}elseif (in_array($matched['op'], array('=','!=','<','>','<=','>='))) {
			//线性操作符，值不能为array
			if (is_array($colValue)) {
					$errMsg=sprintf('the value of the colunm %s must not be a array,because the specific operator is %s',$colName,$matched['op']);
					throw new Pfinal_Exception_Runtime($errMsg);
			}
			//线性操作符，值不能为空,包括空字符串,空的0可以通过
			if (empty($colValue)&&!isset($colValue)) {
				$errMsg=sprintf('the value of the colunm %s must not be empty,because the specific operator is %s',$colName,$matched['op']);
				throw new Pfinal_Exception_Runtime($errMsg);
			}
			//如果值为字符串，则默认用‘号包裹
			if (is_string($colValue)) {
				$prefix = isset($this->alias)?$this->alias:$this->tableName;
				$this->whereCols[]=array($op,sprintf('%s.%s%s%s',$prefix,$matched['key'],$matched['op'],'\''.$colValue.'\''));
			}else{
				$prefix = isset($this->alias)?$this->alias:$this->tableName;
				$this->whereCols[]=array($op,sprintf('%s.%s%s%s',$prefix,$matched['key'],$matched['op'],$colValue));
			}			
		}elseif(in_array($matched['op'],array('like'))){
			//线性操作符，值不能为array
			if (is_array($colValue)) {
					$errMsg=sprintf('the value of the colunm %s must not be a array,because the specific operator is %s',$colName,$matched['op']);
					throw new Pfinal_Exception_Runtime($errMsg);
			}
			//线性操作符，值不能为空,包括空字符串,空的0可以通过
			if (empty($colValue)&&!isset($colValue)) {
				$errMsg=sprintf('the value of the colunm %s must not be empty,because the specific operator is %s',$colName,$matched['op']);
				throw new Pfinal_Exception_Runtime($errMsg);
			}
			$prefix = isset($this->alias)?$this->alias:$this->tableName;
				//table.col like '%asda%'
			$this->whereCols[]=array($op,sprintf("%s.%s %s '%s%s%s'",$prefix,$matched['key'],$matched['op'],'%',$colValue,'%'));
		}else{
			$errMsg=sprintf('unsupported operator[%s] given in %s',$matched['op'],$matched['key']);
			throw new Pfinal_Exception_Runtime($errMsg);
		}
		return $this;
	}
	
	/**
	 * 
	 * @param unknown_type $colName
	 * @param unknown_type $colValue
	 * @return Pfinal_Model_Statement
	 */
	public function where($colName,$colValue){
		return $this->_where($colName, $colValue,'AND');
	}
	
	public function orWhere($colName,$colValue){
		return $this->_where($colName, $colValue, 'OR');
	}
	
	/**
	 * 
	 * @throws StatementException
	 * @return unknown|NULL
	 */
	public function getWhere(){
		return $this->_where;
	}
	
	
	/**
	 * @return the $alias
	 */
	public function getAlias() {
		return $this->alias;
	}

	/**
	 * @return the $orderClause
	 */
	public function getOrderClause() {
		return $this->orderClause;
	}

	/**
	 * @return the $groupClause
	 */
	public function getGroupClause() {
		return $this->groupClause;
	}

	/**
	 * @return the $count
	 */
	public function getCount() {
		return $this->count;
	}

	/**
	 * @return the $offset
	 */
	public function getOffset() {
		return $this->offset;
	}

	/**
	 * @return the $whereCols
	 */
	public function getWhereCols() {
		return $this->whereCols;
	}

	/**
	 * @param multitype: $alias
	 */
	public function setAlias($alias) {
		$this->alias = $alias;
	}

	/**
	 * @param multitype: $orderClause
	 */
	public function setOrderClause($orderClause) {
		$this->orderClause = $orderClause;
	}

	/**
	 * @param multitype: $groupClause
	 */
	public function setGroupClause($groupClause) {
		$this->groupClause = $groupClause;
	}

	/**
	 * @param unknown_type $count
	 */
	public function setCount($count) {
		$this->count = $count;
	}

	/**
	 * @param unknown_type $offset
	 */
	public function setOffset($offset) {
		$this->offset = $offset;
	}

	/**
	 * @param multitype: $fields
	 */
	public function setFields($fields) {
		$this->fields = $fields;
	}

	/**
	 * @param multitype: $whereCols
	 */
	public function setWhereCols($whereCols) {
		$this->whereCols = $whereCols;
	}
	

	/**
	 * @param multitype: $_where
	 */
	public function setWhere($_where) {
		$this->_where = $_where;
	}
	
}

?>